/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package transformGrammar;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;

import Utils.Proprietati;


/**
 *
 * @author daniel
 */
public class TransformGrammar {

    public static final String add = //"options\n"
            //+ "{\n"
            //+ "	backtrack = true;\n"
            //+ "	k=6;\n"
            //+ "	output = AST;\n"
            //+ "}\n"
            /*+*/ "$toFile"
            + "@header {\n"
            + "   import gettree.*;\n"
            + "}\n"
            + "@parser::members{\n"
            + "	 gettree.Tree tree = new gettree.Tree();\n"
            + "  gettree.TreeNode currentNode = tree.getRoot();\n"
            + "  gettree.TreeNode prov;\n"
            + "}\n";
    public static final String rewr = "->^($)";
    public static StringBuilder toFile = new StringBuilder(); 
    public static HashMap<String,String> Tokens = new HashMap<String, String>(); 
    public static String lineSep = System.getProperty("line.separator");
    public static String restoreparent = " {currentNode=(gettree.TreeNode)currentNode.getParent();}";
    public static File transform(File grammar) throws FileNotFoundException, IOException {
        toFile.delete(0, toFile.length());
        Tokens.clear();
        String grammar_name = grammar.getName();
        grammar_name = grammar_name.substring(0, grammar_name.indexOf("."));
        File mgrammar = new File(grammar.getParentFile().getCanonicalPath() + "\\" + grammar_name + "M.g");

        BufferedReader br = new BufferedReader(new FileReader(grammar));
        BufferedWriter out = new BufferedWriter(new FileWriter(mgrammar));
        String strLine;
        strLine = br.readLine();

        // citim numele gramaticii
        while (strLine.trim().equals("")) {
            strLine = br.readLine();
        }
        
        StringBuffer options =  new StringBuffer();
        strLine = br.readLine();
        while (!strLine.contains("}")) {
        	options.append(strLine);
            strLine = br.readLine();
        }
        if(!options.toString().contains("output = AST;") && !strLine.contains("output = AST;"))
        	options.append("output = AST;\n");
        options.append(strLine);
        toFile.append("grammar " + grammar_name + "M;\n");
        toFile.append(options);
        toFile.append(add);
        //out.write("grammar " + grammar_name + "M;\n");
        //out.write(add);
        // citim pana la prima regula si scriem in output
        char c = 0;
        StringBuffer buffer = new StringBuffer();
        StringBuffer pname = new StringBuffer();
        String base = "";
        String addr = "{rules.add($);}";
        boolean start = false;
        boolean not = true;
        boolean first = true;
        char p = ' ';

        while ((c = (char) br.read()) != -1) {
            if (c == '\uffff') {
                break;
            }
            if (start) {
                buffer.append(c);
                if (start && c == ';' && not && p != '\'') {
                    // delete last ';'
                    //System.out.println(buffer.substring(0, buffer.lastIndexOf(";")));
                    String[] split = buffer.substring(0, buffer.lastIndexOf(";")).split("\\|");
                    for (int j = 0; j < split.length; j++) {
                        if (!base.toUpperCase().equals(base)) {
                            toFile.append(addr.replace("$", "\"" + base + "_" +j + "\"") + split[j].trim() );
                            toFile.append(constructTree(split[j], base + j));
                            toFile.append((j != split.length - 1 ? "\n\t|" : "\n\t;"));
                        } else {
                            toFile.append(split[j] + (j != split.length - 1 ? "\n\t|" : ";"));
                            //out.write(split[j] + (j != split.length - 1 ? "\n\t|" : ";"));
                        }
                       // out.flush();
                    }
                    buffer.delete(0, buffer.length());
                    start = false;
                    pname.delete(0, pname.length());
                    base = "";
                }
                p = c;
                continue;
            } else {
                
                toFile.append(c);
                //out.write(c);
                //out.flush();
            }
            if (c == ':') {
                char c2 = (char) br.read();
                if (c2 != ':' && p != '\'') {
                    base = pname.toString().trim();
                    start = true;
                }
            } else {
                pname.append(c);
                if ((c == '}' | c == '{' | c == ';') && not) {
                    pname.delete(0, pname.length());
                }
            }
        }
        StringBuilder tok = new StringBuilder();
        tok.append("tokens {\n");
        for (String k : Tokens.keySet()){
            tok.append("\t"+Tokens.get(k)+"="+k +";\n");
        }
        tok.append("}\n");
        int idxop1 = toFile.lastIndexOf("option");
        int i ;
        for ( i = idxop1 ; i< toFile.length() ; i++){
            if (toFile.charAt(i)=='}')
                break;
        }
        //System.out.println(toFile.substring(idxop1, i+1));
        //System.out.println();
        toFile.delete(idxop1, i+1);
        out.write(toFile.toString().replace("$toFile", tok.toString()));
        out.flush();
        out.close();
        p = c;
        return mgrammar;
    }

    public static String constructTree(String subrule,String ruleName) {
        if (subrule.indexOf("'") < 0) {
            return "";//rewr.replace("$", subrule.trim()).trim().replaceAll(lineSep, "");
        }
        StringBuffer rez = new StringBuffer();
        StringBuffer label = new StringBuffer();
        boolean tok = true;
        for (int i = 0; i <= subrule.length() && i >=0;) {
            i = subrule.indexOf("'");
            if (i==0){
                tok=false;
                subrule=subrule.substring(1);
            }
            if (i > 0) {
                while (subrule.charAt(i - 1) == '\\') {
                    i = subrule.indexOf("'");
                }
                if (tok) {
                    rez.append(subrule.substring(0, i).trim() + " ");
                } else {
                    label.append(subrule.substring(0, i).trim() + " ");
                }
                tok=!tok;
                subrule = subrule.substring(i+1);
                i=1;
            }

        }
        try {
        	Tokens.put( "'"+label.toString().trim()+"'",ruleName.toUpperCase());
        }
        catch (Exception e) {
			// TODO: handle exception
		}
        rez.append(subrule);
        return rewr.replace("$","'"+label.toString().trim() + "' "  +  rez.toString()).trim().replaceAll(lineSep, "");
    }
   
    
    public static String constructTreeWLabel(String subrule) {
        
    	// check if the rule is an token 
    	// if it is return this one
    	subrule = subrule.trim();
    	if (subrule.startsWith("'")&& subrule.endsWith("'") && subrule.split("'").length==2)
    		return subrule;
    	
        if (subrule.indexOf("'") < 0) {
            return subrule.trim().replaceAll(lineSep, "");
        }
        StringBuffer rez = new StringBuffer();
        StringBuffer label = new StringBuffer();
        boolean tok = true;
        for (int i = 0; i <= subrule.length() && i >=0;) {
            i = subrule.indexOf("'");
            if (i==0){
                tok=false;
                subrule=subrule.substring(1);
            }
            if (i > 0) {
                while (subrule.charAt(i - 1) == '\\') {
                    i = subrule.indexOf("'");
                }
                if (tok) {
                    rez.append(subrule.substring(0, i).trim() + " ");
                } else {
                    label.append(subrule.substring(0, i).trim() + " ");
                }
                tok=!tok;
                subrule = subrule.substring(i+1);
                i = 1;
            }

        }
        rez.append(subrule);
        return rez.toString().trim().replaceAll(lineSep, "");
    }
    
    
public static File addGetParsedTree(File grammar) throws FileNotFoundException, IOException {
        // delete old to file
		toFile.delete(0, toFile.length());
        // get grammar file name
		String grammar_name = grammar.getName();
        grammar_name = grammar_name.substring(0, grammar_name.indexOf("."));
        // create new file - to write modified grammar
        File mgrammar = new File(/*grammar.getParentFile().getCanonicalPath() + "\\"*/Proprietati.modGrammarOut + "\\" + grammar_name + "TreePG.g");
        BufferedReader br = new BufferedReader(new FileReader(grammar));
        BufferedWriter out = new BufferedWriter(new FileWriter(mgrammar));
        String strLine;
        strLine = br.readLine();
        // citim numele gramaticii
        while (strLine.trim().equals("")) {
            strLine = br.readLine();
        }
        StringBuffer options =  new StringBuffer();
        strLine = br.readLine();
        while (!strLine.contains("}")) {
        	options.append(strLine);
            strLine = br.readLine();
        }
        options.append(strLine);
        if(!options.toString().contains("AST")){
        	options = new StringBuffer(options.toString().replace("}", "output = AST;\n\t}\n"));
        }
       // options.append(strLine);
        // write new grammar name 
        toFile.append("grammar " + grammar_name + "TreePG;\n");
        // write grammar options
        options.append("\n");
        toFile.append(options);
        toFile.append(add);
        // citim pana la prima regula si scriem in output
        char c = 0;
        StringBuffer buffer = new StringBuffer();
        StringBuffer pname = new StringBuffer();
        String base = "";
        String addr = "{ prov = new TreeNode(null,\"\",null); prov.setLabel($); currentNode.addChild(prov);currentNode= prov;}";
        boolean start = false;
        boolean not = true;
        char p = ' ';

        while ((c = (char) br.read()) != -1) {
            if (c == '\uffff') {
                break;
            }
            if (start) {
                buffer.append(c);
                if (start && c == ';' && not && p != '\'') {
                    // delete last ';'
                    String[] split = buffer.substring(0, buffer.lastIndexOf(";")).split("\\|");
                    if(base.contains("fragment"))
                    	base = base.replace("fragment", "");
                    for (int j = 0; j < split.length; j++) {
                        	
                    	if (!base.trim().toUpperCase().equals(base.trim())) {
                            toFile.append(addr.replace("$", "\"" + base +"_" + j + "\"") + split[j].trim() );
                            toFile.append( restoreparent + " " + (j != split.length - 1 ? "\n\t|" : "\n\t;"));
                        } else {
                            toFile.append(split[j] + (j != split.length - 1 ? "\n\t|" : ";"));
                            
                        }
                       
                    }
                    buffer.delete(0, buffer.length());
                    start = false;
                    pname.delete(0, pname.length());
                    base = "";
                }
                p = c;
                continue;
            } else {
                toFile.append(c);
            }
            if (c == ':') {
                char c2 = (char) br.read();
                if (c2 != ':' && p != '\'') {
                    base = pname.toString().trim();
                    start = true;
                }
            } else {
                pname.append(c);
                if ((c == '}' | c == '{' | c == ';') && not) {
                    pname.delete(0, pname.length());
                }
            }
        }
        //int idxop1 = toFile.lastIndexOf("option");
        //int i ;
        //for ( i = idxop1 ; i< toFile.length() ; i++){
        //    if (toFile.charAt(i)=='}')
        //        break;
        //}        
        //toFile.delete(idxop1, i+1);
        out.write(toFile.toString().replace("$toFile", ""));
        out.flush();
        out.close();
        p = c;
        return mgrammar;
    }

    public static void main(String args[]) throws FileNotFoundException, IOException {
        addGetParsedTree(new File ("G:\\workspace\\FindAntlrRules\\inp\\impSS.g"));
        //System.out.println(constructTree("'if' bExp 'then' '(' stmt ')''else' '(' stmt ')'", "fgh"));
        //System.out.println(constructTreeWLabel("'if' bExp 'then' '(' stmt ')''else' '(' stmt ')'"));
        
    }
}
